/*
 * Flota.h
 *
 *  Created on: 09/01/2010
 *      Author: San Martín, Matías I.
 */

#ifndef FLOTA_H_
#define FLOTA_H_

#include <list>
#include <iostream>
#include <cstdlib>
#include <cmath>

#include "../../Common/CommonTypes.h"
#include "../../Utiles/Posicion.h"
#include "../../../Middleware/Common/IdFlota.h"
#include "../../../Framework/IO/SerializableToCharArray.h"

#include "Nave.h"

namespace aplicacion {

typedef std::list<Nave> t_naves;
typedef std::list<const Nave*> t_constPtrNaves;

class Flota : public framework::io::SerializableToCharArray {
//------------------------------ CONSTANTES ------------------------------
public:

//--------------------------- ATRIBUTOS ------------------------------------
private:
	/** Identificador unívoco de la flota (local a un jugador) */
	IdFlota _identificador;
	T_TIEMPO _tahora;
	Posicion _destino;
	t_naves _naves;

//------------------------------ METODOS ------------------------------
public:
	Flota(const IdFlota& id, int cantidadNaves, T_SEMILLA semilla,
			double escalaDistribucion,
			const Posicion& posPartida, const Posicion& posDestino,
			T_TIEMPO tiempoActual);

	/** Este constructor crea una flota sin naves pero con un id definido,
	 * se puede cargar el estado mediante el metodo "load"*/
	Flota(const IdFlota& id);

	/**
	 * Crea una flota sin estado.
	 * Se debe recuperar el estado luego (por ejemplo, con el metodo load)
	 */
	Flota();

	virtual ~Flota();

	/**
	 * Permite asignar el tiempo desplazando todos los arribos como
	 * si el tiempo asignado fuera el acual
	 */
	void cambiarTiempo(T_TIEMPO tiempo);

	/**
	 * Permite establecer el tiempo en el indicado
	 *
	 * @tiempo tiempo a asignar
	 *
	 * @return cantidad de naves de la flota que arribaron a destino
	 */
	size_t setTiempo(T_TIEMPO tiempo);

	/**
	 * Permite obtener la cantidad de naves que arribaran hasta el tiempo
	 * indicado
	 *
	 * @tiempo tiempo a limite para contar los arribos
	 *
	 * @return cantidad de naves de la flota que arribaran a destino para
	 * 			el tiempo indicado
	 *
	 * (este método devuelve el mismo numero que una llamada a setTiempo
	 * pero, a diferencia de este, no remueve las naves de la flota)
	 */
	size_t arribaran(T_TIEMPO tiempo) const;

	T_TIEMPO getAhora() const
	{
		return _tahora;
	}


	const Posicion& getDestino() const
	{
		return _destino;
	}

	size_t getCantidadNaves() const
	{
		return _naves.size();
	}

	bool operator == (const IdFlota& id) const;

	const IdFlota& getId() const;

	void setId(const IdFlota& id);

	const IdJugador& getDuenio() const
	{
		return _identificador.getIdJugador();
	}

//	T_SEMILLA getSemillaCreacion() const;

	/**
	 * Devuelve las naves de la flota ordenadas por tiempo (creciente)
	 * hasta el tiempo indicado (inclusive).
	 *
	 * El invocador se debe encargar de liberar la memoria reservada para
	 * la lista del resultado
	 */
	t_constPtrNaves* getNavesPorTiempoHasta(T_TIEMPO tiempoHasta) const;

	/**
	 * Devuelve las naves de la flota ordenadas por tiempo (creciente)
	 * hasta la cantidad de naves indicada.
	 *
	 * El invocador se debe encargar de liberar la memoria reservada para
	 * la lista del resultado
	 */
	t_constPtrNaves* getNavesPorTiempoHastaCantidad(size_t cantidadHasta) const;

	//-------------------- de interfaz framework::io::SerializableToFile
	/**
	 * @see framework::io::SerializableToFile#save(int)
	 *
	 * Se guarda todo menos el identificador de flota
	 */
	virtual size_t save (int fd) const;

	/**
	 * @see framework::io::SerializableToFile#load(int)
	 *
	 * ya que no se guardo el identificador de flota, no se puede recuperar,
	 * debera ser asignado luego
	 */
	virtual size_t load (int fd);

	/**
	 * @see middleware::io::SerializableToArray#saveToArray(int)
	 */
	virtual size_t saveToArray (uint8_t* arr) const;

	/**
	 * @see middleware::io::SerializableToArray#loadFromArray(int)
	 */
	virtual size_t loadFromArray (const uint8_t* arr);

private:
	void actualizarTamanio();

	//genera un numero con probabilidad exponencial
	double randExponencial(double media){
		return media * -log(((double)rand()) /RAND_MAX);
	}

	void generarNaves(const Posicion& posPartida, const Posicion& posDestino,
					int cantidadNaves, T_SEMILLA semilla, double escalaDistribucion);

};

} //namespace aplicacion

#endif /* FLOTA_H_ */
